package com.apobates.jforum.grief.schema2doc.reactive.dialect;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.entity.Column;
import com.apobates.jforum.grief.schema2doc.core.entity.Nullable;
import com.apobates.jforum.grief.schema2doc.core.entity.PrimayKey;
import com.apobates.jforum.grief.schema2doc.core.entity.Table;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import com.apobates.jforum.grief.schema2doc.reactive.schema.AbstractRxJavaQueryExecutor;
import io.reactivex.Flowable;
import io.reactivex.Single;
import org.davidmoten.rx.jdbc.Database;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Optional;

/**
 * RxJava2的MySQL的结果集供应商
 * https://github.com/davidmoten/rxjava-jdbc
 */
public class RxJavaMySQLExecutor extends AbstractRxJavaQueryExecutor {

    private final static Logger logger = LoggerFactory.getLogger(RxJavaMySQLExecutor.class);

    public RxJavaMySQLExecutor(Database db, SchemaDialect dialect) {
        super(db, dialect);
    }

    @Override
    protected Flowable<Table> getTables(Database db, Optional<String> dbName, Optional<String> schema, SchemaTableStrategy tableStrategy) throws IllegalArgumentException {
        String sql = "SELECT TABLE_NAME AS tableName, TABLE_COMMENT AS remarks FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = :dbname";
        if(tableStrategy.sql(SchemaDialect.MySQL).isPresent()){
            sql+= " AND " + tableStrategy.sql(SchemaDialect.MySQL).get().replaceAll(SchemaTableStrategy.placeholder, "TABLE_NAME");
        }
        logger.debug("[RxJava-MySQL-Table]Query Table, Db::"+dbName.get());
        return db
                .select(sql)
                .parameter("dbname", dbName.get())
                .get(rs-> Table.noSchema(0, dbName.get(),
                        rs.getString("tableName"),
                        rs.getString("remarks")))
                .filter(table->tableStrategy.filter().test(table.getTableName()));
    }

    @Override
    protected Single<List<Column>> getColumns(Database db, Table table) {
        String sql = "SELECT " +
                "COLUMN_NAME AS columnName, " +
                "DATA_TYPE AS typeName, " +
                "REPLACE(REPLACE(REPLACE(COLUMN_TYPE, DATA_TYPE, ''), '(', ''), ')', '') AS columnSize, " +
                "IF(IS_NULLABLE='NO','2','1') AS nullable, " +
                "COLUMN_COMMENT AS remarks, " +
                "COLUMN_DEFAULT AS columnDef, " +
                "IF(COLUMN_KEY='PRI','1','2') AS pk, " +
                "NUMERIC_SCALE AS decimalDigits " +
                "FROM INFORMATION_SCHEMA.COLUMNS " +
                "WHERE TABLE_SCHEMA = :dbname AND TABLE_NAME = :tablename";
        logger.debug("[RxJava-MySQL-Column]Query Column::"+table);
        // basic(String columnName, String typeName, String columnSize, Nullable nullable, String remarks)
        return db.select(sql)
                .parameter("dbname", table.getDbName())
                .parameter("tablename", table.getTableName())
                .get(rs-> Column.basic(
                                rs.getString("columnName"),
                                rs.getString("typeName"),
                                rs.getString("columnSize"),
                                Nullable.of(rs.getInt("nullable")),
                                rs.getString("remarks"))
                        .toFull(
                                rs.getString("decimalDigits"),
                                PrimayKey.of(rs.getInt("pk")),
                                rs.getString("columnDef")))
                .toList();
    }
}
